package javadeploylogic

import (
	"context"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"sync"
	"time"
	"yunzhan/common/models"
	utils "yunzhan/common/utils"
	"yunzhan/rpc-server/internal/svc"
	agent "yunzhan/rpc-server/pb"
)

type DeployJavaLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDeployJavaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeployJavaLogic {
	return &DeployJavaLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *DeployJavaLogic) DeployJava(in *agent.DeployJavaRequest) (*agent.DeployResponse, error) {
	if in.NodeInfo == nil {
		return &agent.DeployResponse{
			Code:    500,
			Message: fmt.Sprintf("未配置节点信息, 无法执行 JDK 部署"),
		}, errors.New(fmt.Sprintf("未配置节点信息, 无法执行 JDK 部署"))
	}

	resp := &agent.DeployResponse{
		Code:    200,
		Message: fmt.Sprintf("请求已接收，正在部署 %s 到节点 %s", in.ConfigInfo.ComponentName, in.NodeInfo.Host),
	}

	go l.startDeployment(in)

	return resp, nil
}
func (l *DeployJavaLogic) startDeployment(in *agent.DeployJavaRequest) {

	// 创建 LogManager 实例
	logManager := models.NewLogManager(100, fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port))
	defer logManager.Close()

	flushInterval := 5 * time.Second // 刷新间隔
	maxBatchSize := 100              // 最大批量大小
	retryDelay := 2 * time.Second    // 重试延迟
	maxRetries := 3                  // 最大重试次数

	// 创建 ComponentInfoManager 实例
	componentInfoManager := models.NewComponentInfoManager(
		1000,
		fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port),
		flushInterval,
		maxBatchSize,
		retryDelay,
		maxRetries)
	defer componentInfoManager.Close()

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()

		packageDirectory := in.ConfigInfo.PackagePath
		rtrimDir := utils.Rtrim(packageDirectory, "/")
		javaVersion := in.ConfigInfo.ComponentName

		path := in.ConfigInfo.InstallPath
		if path == "" {
			path = "/usr/local"
		}

		installPath := utils.Rtrim(path, "/")
		baseInfo := fmt.Sprintf("安装包存放目录: %s, JDK version: %s, JDK 安装目录: %s", rtrimDir, javaVersion, installPath)
		step := 1
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", baseInfo, "JDK", "Server")

		checkPathCommand := fmt.Sprintf(`
if [ ! -d "%s" ]; then
   sudo mkdir -p "%s"
fi
`, installPath, installPath)
		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "执行组件安装路径检查...", "JDK", "Client")
		output, err := utils.ExecCommand(checkPathCommand)
		if err != nil {
			message := fmt.Sprintf("检查组件安装路径失败: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "检查组件安装路径完成", "JDK", "Client")

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "解压安装包...", "JDK", "Client")
		tarCommand := fmt.Sprintf("sudo tar -xzf %s/%s -C %s", rtrimDir, javaVersion, installPath)
		output, err = utils.ExecCommand(tarCommand)
		if err != nil {
			message := fmt.Sprintf("解压安装包失败: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "解压安装包完成", "JDK", "Client")

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "备份profile文件...", "JDK", "Client")
		cpCommand := fmt.Sprintf("sudo cp /etc/profile /etc/profile.bak")
		output, err = utils.ExecCommand(cpCommand)
		if err != nil {
			message := fmt.Sprintf("备份profile文件异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "备份profile文件完成", "JDK", "Client")

		appendEnvCommand := fmt.Sprintf(`
sudo bash -c 'cat <<EOF >>/etc/profile
export JAVA_HOME=%s/java
export CLASSPATH=.:\${JAVA_HOME}/jre/lib/rt.jar:\${JAVA_HOME}/lib/dt.jar:\${JAVA_HOME}/lib/tools.jar
export PATH=$PATH:\${JAVA_HOME}/bin
EOF'
`, installPath)
		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "添加Java环境变量...", "JDK", "Client")
		output, err = utils.ExecCommand(appendEnvCommand)
		if err != nil {
			message := fmt.Sprintf("添加Java环境变量异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "添加Java环境变量完成", "JDK", "Client")
		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "刷新Java环境变量...", "JDK", "Client")
		sourceCommand := fmt.Sprintf("bash -c 'source /etc/profile && exec bash'")
		_, err = utils.ExecCommand(sourceCommand)
		if err != nil {
			message := fmt.Sprintf("刷新Java环境变量异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", "Java部署成功", "JDK", "Client")

		//step++
		//checkVersion := fmt.Sprintf(`source /etc/profile && java -version`)
		//output, err = utils.ExecCommand(checkVersion)
		//if err != nil {
		//	message := fmt.Sprintf("刷新Java环境变量异常: %v, output: %s", err, output)
		//	logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
		//	return
		//}
		//logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", fmt.Sprintf("Java Version: \n %s", output), "JDK", "Client")

		currentIP, currentIPErr := utils.GetCurrentInternalIP()
		if err != nil {
			message := fmt.Sprintf("%s: 无法获取当前主机IP: %v", in.NodeInfo.Host, currentIPErr)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}
		currentHost, currentHostErr := utils.GetCurrentHostname()
		if err != nil {
			message := fmt.Sprintf("%s: 无法获取当前主机名: %v", in.NodeInfo.Host, currentHostErr)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "ERROR", message, "JDK", "Client")
			return
		}

		javaInfo := &models.ComponentInfo{
			ClusterID:      in.ClusterID,
			ComponentName:  "JDK",
			Version:        in.Version,
			NodeHost:       currentHost,
			NodeIP:         currentIP,
			ComponentRole:  "Client",
			HomePath:       installPath + "/java",
			DataStorageDir: "",
			Port:           "",
			Status:         true,
			AdditionalInfo: "",
		}

		componentInfoManager.SendComponentInfo(javaInfo)

	}()

	wg.Wait()
}
